package com.easyJava.builder;

import com.easyJava.bean.*;
import javafx.scene.control.Tab;
import javafx.scene.control.ToolBar;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.xml.XMLConstants;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.Buffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.easyJava.bean.XmlConstants.*;
import static com.easyJava.builder.BuildMapper.*;

/**
 * 生成XML的类
 */

public class BuildMapperXml {

    private static final Logger logger = LoggerFactory.getLogger(BuildMapper.class);


    private static final String namespace = "<mapper namespace=\"";


    private static final String BASE_RESULT_MAP = "base_result_map";


    public static final String END_XML = "</mapper>";


    public static final String RESULTMAP = "resultMap";

    public static final String ID = "id";

    public static final String RESULT = "result";

    //sqlType
    public static final String COLUMN = "column";

    //javaType
    public static final String PROPERTY = "property";


    public static final String PRIMARY_KEY = "PRIMARY";


    public static final String SQl = "sql";

    public static final String TEST= "test";

    public static final String IF = "if";

    public static final String QUERY = "query.";

    public static final String NOTNULL = " != null ";


    public static final String BASE_COLUMN_LIST ="base_column_list";

    public static final String BASE_CONDITION_FILED = "base_condition_filed";

    public static final String QUERY_CONDITION = "query_condition";
    public static final String SELECTCOUNTNAME = "selectCount";
    public static final String RESULTTYPE = "resultType";


    public static final String COUNT = "count(1)";
    /**
     * 生成xml文件
     * @param tableInfo
     */
    public static void execute(TableInfo tableInfo){
        File folder = new File(Constants.PATH_MAPPER_XML);
        if(!folder.exists()){
            folder.mkdirs();
        }
        String package_xml = tableInfo.getBeanName() + Constants.MAPPER_NAME;
        File file_mapper = new File(folder,package_xml+".xml");
        OutputStream outputStream =null;
        OutputStreamWriter outputStreamWriter = null;
        BufferedWriter bufferedWriter = null;

        try{
            outputStream = new FileOutputStream(file_mapper);
            outputStreamWriter = new OutputStreamWriter(outputStream,"utf-8");
            bufferedWriter = new BufferedWriter(outputStreamWriter);

            //xml 的开头
            bufferedWriter.write(ClassType.XML_HEADER);
            bufferedWriter.newLine();
            bufferedWriter.write(namespace + Constants.PACKAGE_MAPPER +"."+package_xml+"\">");

            //实体映射
            EntityMapper(tableInfo,bufferedWriter,package_xml);
            //通用查询结果列
            SelectAllSql(tableInfo,bufferedWriter);
            //SQl的总和
            AllSQl(tableInfo,bufferedWriter);
            //查询集合语句的创建
            MakeSelect(tableInfo,bufferedWriter);
            bufferedWriter.newLine();
            //查询数量
            CountNum(tableInfo,bufferedWriter);
            // 插入(匹配有值的字段）
            insertKeyValues(bufferedWriter,tableInfo);
            //插入或者更新 （匹配有值的字段）
            insertOrUpdate(bufferedWriter,tableInfo);
            //添加 （批量插入）
            insertBatch(bufferedWriter,tableInfo);
            //批量新增修改 （批量插入）
            insertOrUpdateBatch(bufferedWriter,tableInfo);
            //多条件修改
            updateByParam(bufferedWriter,tableInfo);
            //多条件删除
            deleteByParam(bufferedWriter,tableInfo);
            //根据Key获得对象
            keyAll(tableInfo,bufferedWriter);
            bufferedWriter.write(END_XML);
            bufferedWriter.flush();
        }catch (Exception e){
            logger.error("生成mapper文件失败",e);
        }finally {
            try {
                bufferedWriter.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            try {
                outputStreamWriter.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            try {
                outputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 处理Key的问题
     * @param tableInfo
     * @param bw
     * @throws Exception
     */

    public static void keyAll(TableInfo tableInfo ,BufferedWriter bw ) throws Exception{
        for(Map.Entry<String,List<FieldInfo>> entry:tableInfo.getKeyIndexMap().entrySet()){
            String key = entry.getKey();
            List<FieldInfo> KeyList = entry.getValue();
            String properName =  KeyList.get(0).getPropertyName().substring(0,1).toUpperCase() + KeyList.get(0).getPropertyName().substring(1);
            //如果是联合主键
            if(KeyList.size() !=1){
                properName = new String();
                for (int i = 0; i < KeyList.size(); i++) {
                    if( i  == KeyList.size() - 1){
                        properName += KeyList.get(i).getPropertyName().substring(0,1).toUpperCase() + KeyList.get(i).getPropertyName().substring(1);
                    }else {
                        properName += KeyList.get(i).getPropertyName().substring(0,1).toUpperCase() + KeyList.get(i).getPropertyName().substring(1) + BuildMapper.AND;
                    }
                }
            }
            updateById(bw,tableInfo,KeyList,BuildComment.ACCORDING + properName + UPDATE_WORK , XmlConstants.UPDATE + "By" + properName);
            deleteById(bw,tableInfo,KeyList,BuildComment.ACCORDING + properName + DELETE_WORK , XmlConstants.DELETE + "By" + properName);
            selectById(bw,tableInfo,KeyList,BuildComment.ACCORDING + properName + SELECT_WORK , XmlConstants.SELECT + "By" +properName );

        }
    }


    /**
     * 根据Key获得对象
     * @param bw
     * @param tableInfo
     * @throws Exception
     */
    public static void selectById(BufferedWriter bw, TableInfo tableInfo, List<FieldInfo> KeyList,String comment ,String Id) throws Exception{
        bw.newLine();
        bw.write("\t<!-- "+ comment + "-->\n");
        bw.write("\t<" + XmlConstants.SELECT + " " + ID + "=\"" + Id + "\" " + RESULTMAP + "=\"" + BASE_RESULT_MAP + "\" >\n");
        bw.write("\t\t" +XmlConstants. SELECT + " <" + INCLUDE + " " + REFID + "=\"" + BASE_COLUMN_LIST + "\" />");
        bw.write("\t\t" + FROM + " " + tableInfo.getTableName() + "\n");
        WhereKey(bw,KeyList);
        bw.write("\t</" + XmlConstants.SELECT + ">\n");
    }


    /**
     * 根据Id删除
     * @param bw
     * @param tableInfo
     * @throws Exception
     */
    public static void deleteById(BufferedWriter bw,TableInfo tableInfo,List<FieldInfo> KeyList,String comment ,String Id) throws Exception{
        bw.newLine();
        bw.write("\t<!-- "+ comment + "-->\n");
        bw.write("\t<" +XmlConstants. DELETE + " "+ ID + "=\"" + Id + "\" >\n");
        bw.write("\t\t" +XmlConstants. DELETE + " " + FROM +" "+  tableInfo.getTableName() + "\n");
        WhereKey(bw,KeyList);
        bw.write("\t</" + XmlConstants.DELETE + ">\n");
    }


    /**
     * 根据Id修改
     * @param bw
     * @param tableInfo
     * @throws Exception
     */
    public static void updateById(BufferedWriter bw,TableInfo tableInfo,List<FieldInfo> KeyList,String comment ,String Id)throws Exception{
        bw.newLine();
        bw.write("\t<!-- "+comment + "-->\n");
        bw.write("\t <" + XmlConstants.UPDATE + " " + ID  + "=\"" + Id+ "\" " + XmlConstants.PARAMETERTYPE + "=\"" + Constants.PACKAGE_PO + "." + tableInfo.getBeanName() + "\">\n");
        bw.write("\t\t" + XmlConstants.UPDATE + " " + tableInfo.getTableName() + "\n");
        DoSet(bw,tableInfo,KeyList);
        WhereKey(bw,KeyList);
        bw.write("\t</" + XmlConstants.UPDATE + ">\n");

    }



    /**
     * 多条件删除
     * @param bw
     * @param tableInfo
     * @throws Exception
     */
    public static void deleteByParam(BufferedWriter bw,TableInfo tableInfo) throws Exception{
        bw.newLine();
        bw.write("\t<!-- "+ XmlConstants.DELETE_BY_PARAM_COMMENT + "-->\n");
        bw.write("\t <" + XmlConstants.DELETE + " " + ID  + "=\"" + XmlConstants.DELETE_BY_PARAM + "\" >\n");
        bw.write("\t\t " +XmlConstants. DELETE +" " + FROM + tableInfo.getTableName() + "\n");
        bw.write("\t\t<" + XmlConstants.INCLUDE + " " + XmlConstants.REFID + "=\"" + QUERY_CONDITION + "\" />\n");
        bw.write("\t</" + XmlConstants.DELETE + ">\n");
    }



    /**
     * 多条件修改
     * @param bw
     * @param tableInfo
     */
    public static void updateByParam(BufferedWriter bw ,TableInfo tableInfo) throws Exception{
        bw.newLine();
        bw.write("\t<!-- "+ XmlConstants.UPDATE_BYPARAM_COMMENT + "-->\n");
        bw.write("\t <" + XmlConstants.UPDATE + " " + ID  + "=\"" + XmlConstants.UPDATEBYPARAM + "\" " + XmlConstants.PARAMETERTYPE + "=\"" + Constants.PACKAGE_PO + "." + tableInfo.getBeanName() + "\">\n");
        bw.write("\t\t" + XmlConstants.UPDATE + " " + tableInfo.getTableName() + "\n");
        DoSet(bw,tableInfo,new ArrayList<>());
        bw.write("\t\t<" + XmlConstants.INCLUDE + " " + XmlConstants.REFID + "=\"" + QUERY_CONDITION + "\" />\n");
        bw.write("\t</" + XmlConstants.UPDATE + ">\n");
    }


    public static void insertOrUpdateBatch(BufferedWriter bw,TableInfo tableInfo)throws Exception{
        bw.newLine();
        bw.write("\t<!-- "+ XmlConstants.insertOrUpdateBatch_COMMENT + "-->\n");
        bw.write("\t<" + XmlConstants.INSERT_NAME +" "+ ID + " =\"" + XmlConstants.INSERTORUPDATEBATCH + "\" " + XmlConstants.PARAMETERTYPE + " =\" "+ Constants.PACKAGE_PO +"."+tableInfo.getBeanName()+ "\"");
        bw.write(" " + XmlConstants.USEGENERATEDKEYS +"=\"" + Boolean.TRUE + "\" " + XmlConstants.KEYPROPERTY + "=\"" + Constants.BEAN_NAME +"."+ tableInfo.getKeyFieldInfo().getPropertyName() + "\">\n");
        DoForEach(bw,tableInfo,true);
        bw.write("\t</" + XmlConstants.INSERT_NAME + ">\n");
    }

    /**
     *  添加 （批量插入）
     * @param bw
     * @param tableInfo
     */

    public static void insertBatch(BufferedWriter bw, TableInfo tableInfo) throws Exception {
        bw.newLine();
        bw.write("\t<!-- "+ XmlConstants.INSERTBATCH_COMMENT + "-->\n");
        bw.write("\t<" + XmlConstants.INSERT_NAME +" "+ ID + " =\"" + XmlConstants.INSERTBATCH + "\" " + XmlConstants.PARAMETERTYPE + " =\" "+ Constants.PACKAGE_PO +"."+tableInfo.getBeanName()+ "\"");
        bw.write(" " + XmlConstants.USEGENERATEDKEYS +"=\"" + Boolean.TRUE + "\" " + XmlConstants.KEYPROPERTY + "=\"" + Constants.BEAN_NAME +"."+ tableInfo.getKeyFieldInfo().getPropertyName() + "\">\n");
        DoForEach(bw,tableInfo,false);
        bw.write("\t</" + XmlConstants.INSERT_NAME + ">\n");
    }

    /**
     * 插入或者更新 （匹配有值的字段）
     * @param bw
     * @param tableInfo
     * @throws Exception
     */
    public static void insertOrUpdate(BufferedWriter bw,TableInfo tableInfo) throws Exception{
        bw.newLine();
        bw.write("\t<!-- "+ XmlConstants.insertOrUpdate_COMMENT + "-->\n");
        bw.write("\t<" + XmlConstants.INSERT_NAME +" "+ ID + " =\"" + XmlConstants.INSERTORUPDATE + "\" " + XmlConstants.PARAMETERTYPE + " =\" "+ Constants.PACKAGE_PO +"."+tableInfo.getBeanName()+ "\">\n");
        bw.write("\t\t" + XmlConstants.INSERT_SQL + tableInfo.getTableName() + "\n");
        TrimDealWith(bw,tableInfo,"(",")",",",false);
        TrimDealWith(bw,tableInfo,"values (",")","," ,false);
        bw.write("\t\t" + XmlConstants.ONDUPLICATEKEYUPDATE + "\n");
        TrimDealWith(bw,tableInfo,"","",",",true);
        bw.write("\t</" + XmlConstants.INSERT_NAME + ">\n");
    }


    /**
     * 插入 （匹配有值的字段）
     * @param bw
     * @param tableInfo
     * @throws Exception
     */

    public static void insertKeyValues(BufferedWriter bw ,TableInfo tableInfo)throws Exception {
        bw.newLine();
        bw.write("\t<!-- "+ XmlConstants.INSERT_COMMENT + "-->\n");
        bw.write("\t<" + XmlConstants.INSERT_NAME +" "+ ID + " =\"" + XmlConstants.INSERT_COMMENT_ID + "\" " + XmlConstants.PARAMETERTYPE + " =\" "+ Constants.PACKAGE_PO +"."+tableInfo.getBeanName()+ "\">\n");
        FieldInfo keyFieldInfo = tableInfo.getKeyFieldInfo();
        if(keyFieldInfo != null )
        {
            bw.write("\t\t<" + XmlConstants.SELECTKEY + " "+ XmlConstants.KEYPROPERTY + "=\"" + Constants.BEAN_NAME +"."+ keyFieldInfo.getPropertyName() +"\" ");
            bw.write(RESULTTYPE + "= \"" + JavaType.Integer +" \" " + XmlConstants.ORDER +"=\""+ XmlConstants.INSERT_AFTER + "\">\n");
            bw.write("\t\t\t " + XmlConstants.SELECT  + " " + XmlConstants.LAST_INSERT_ID + "\n");
            bw.write("\t\t</" + XmlConstants.SELECTKEY + ">\n");
        }
        bw.write("\t\t" + XmlConstants.INSERT_SQL + tableInfo.getTableName() + "\n");
        TrimDealWith(bw,tableInfo,"(",")",",",true);
        TrimDealWith(bw,tableInfo,"values (",")",",",true);
        bw.write("\t</" + XmlConstants.INSERT_NAME + ">\n");
    }


    /**
     * 查询数量
     * @param tableInfo
     * @param bw
     * @throws Exception
     */
    public static void CountNum(TableInfo tableInfo,BufferedWriter bw)throws Exception{
        bw.newLine();
        bw.write("\t<!-- "+ XmlConstants.QUERY_COUNT_COMMENT + "-->\n");
        bw.write("\t <" + XmlConstants.SELECT + " " +ID + "= \"" + SELECTCOUNTNAME + "\" "  + RESULTTYPE + " =\"" + JavaType.Integer + "\" >\n");
        bw.write("\t\t\t" + XmlConstants.SELECT + " " + COUNT + " " +XmlConstants.FROM + " " + tableInfo.getTableName() + " ");
        bw.write("<" + XmlConstants.INCLUDE + " " + XmlConstants.REFID + "= \"" + QUERY_CONDITION +"\" />\n");
        bw.write("\t </" + XmlConstants.SELECT + ">\n");
    }


    /**
     * 查询集合
     * @param tableInfo
     * @param bw
     * @throws Exception
     */
    public static void MakeSelect(TableInfo tableInfo, BufferedWriter bw) throws Exception{
        bw.newLine();
        bw.write("\t<!-- "+ XmlConstants.QUERY_COLLECTIONS_COMMENT + "-->\n");
        bw.write("\t<" + XmlConstants.SELECT + " " + ID + "=\"" + XmlConstants.QUERY_COLLECTIONS_ID + "\" " +RESULTMAP + "=\"" + BASE_RESULT_MAP + "\" >\n");
        bw.write("\t\t"+ XmlConstants.SELECT + " <" + XmlConstants.INCLUDE + " " + XmlConstants.REFID + "=\"" + BASE_COLUMN_LIST + "\" />");
        bw.write(XmlConstants.FROM + " "  + tableInfo.getTableName() +" " );
        bw.write( "<" + XmlConstants.INCLUDE + " " + XmlConstants.REFID + "=\"" + QUERY_CONDITION + "\" />\n");
        XmlConstants.SpecialDoTest(bw,"query.orderBy",false,"order");
        XmlConstants.SpecialDoTest(bw,"query.simplePage",false,"limit");
        bw.write("\t</" + XmlConstants.SELECT + ">\n");
    }

    /**
     * 生成通用查询条件(包含Query所有字段)
     * @param tableInfo
     * @param bw
     * @throws Exception
     */

    public static void AllSQl(TableInfo tableInfo,BufferedWriter bw) throws Exception{
        bw.newLine();
        bw.write("\t<!-- 通用查询条件列-->\n");
        bw.write("\t <" + SQl +" "+ ID + "=\"" + QUERY_CONDITION + "\">\n");
        bw.write("\t\t<" + XmlConstants.WHERE + ">\n");
        bw.write("\t\t\t<" + XmlConstants.INCLUDE_REFID+"=\"" + BASE_CONDITION_FILED + "\"/>\n");
        for(FieldInfo fieldInfo :tableInfo.getExtendFieldInfoList()){
           XmlConstants.FuzzyDoTest(bw,fieldInfo);
        }
        bw.write("\t\t</" + XmlConstants.WHERE + ">\n");
        bw.write("\t</" + SQl + ">\n");
    }

    /**
     * 通用查询结果列
     * @param tableInfo
     * @param bw
     * @throws IOException
     */
    public static void SelectAllSql(TableInfo tableInfo, BufferedWriter bw) throws Exception {
        bw.newLine();
         //1.
         bw.write("\n\t<!-- 通用查询结果列-->");
         bw.write("\n\t <" + SQl +" "+ID + "=\"" +BASE_COLUMN_LIST + "\">" );
         bw.newLine();
         StringBuffer sb = new StringBuffer();
         sb.append("\t\t");
         for (FieldInfo fieldInfo :tableInfo.getFieldInfoList()){
             sb.append(fieldInfo.getFieldName() + ",");
         }
         bw.write(sb.append("\n").toString().substring(0,sb.toString().lastIndexOf(",")));
         bw.write("\n\t</" + SQl + ">\n");
         //2.
         bw.write( "\n\t <" + SQl +" "+ID + "=\"" +BASE_CONDITION_FILED + "\">\n" );
         for (FieldInfo fieldInfo : tableInfo.getFieldInfoList()){
                XmlConstants.EqualDoTest(bw,fieldInfo);
         }
        bw.write("\t</" + SQl + ">\n");
    }

    /**
     *  实体映射
     * @param tableInfo
     * @param bw
     * @param package_xml
     * @throws IOException
     */
    public static void EntityMapper(TableInfo tableInfo,BufferedWriter bw ,String package_xml) throws IOException {
        bw.newLine();
        bw.newLine();
        bw.newLine();
        bw.write("\t<!--实体映射-->");
        bw.newLine();
        bw.write("\t<" + RESULTMAP + " id=\""+BASE_RESULT_MAP+"\" type=\""+Constants.PACKAGE_PO + "."+ tableInfo.getBeanName()+"\">");
        bw.newLine();
        Map<String, List<FieldInfo>> keyIndexMap = tableInfo.getKeyIndexMap();
        FieldInfo PrimeKey = null;
        for(Map.Entry<String,List<FieldInfo>> entry:keyIndexMap.entrySet()){
            List<FieldInfo> fieldInfoList = entry.getValue();
            String key = entry.getKey();
            if(fieldInfoList.size() == 1 &&  PRIMARY_KEY.equals(key)){
                PrimeKey = fieldInfoList.get(0);
            }
        }
        tableInfo.setKeyFieldInfo(PrimeKey);
        for (FieldInfo fieldInfo : tableInfo.getFieldInfoList()){
            bw.write("\t\t<!--"+ fieldInfo.getComment() + "-->");
            bw.newLine();
            String result = RESULT;
            if(PrimeKey != null && PrimeKey.getFieldName().equals(fieldInfo.getFieldName())) {
                result = ID;
            }
            bw.write("\t\t<" + RESULT + " " + COLUMN + "=\"" + fieldInfo.getFieldName() + "\" " + PROPERTY + "=\"" + fieldInfo.getPropertyName() + "\" />");
            bw.newLine();
        }
        bw.write("\t</" + RESULTMAP + ">");
    }

    public static void main(String[] args) {
        System.out.println(Constants.MAPPER_NAME);
    }
}
